﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;

namespace ListItemEditor.UI.FileDlg
{
    public static class NativeMethods
    {
        [StructLayout(LayoutKind.Sequential), SuppressUnmanagedCodeSecurity]
        public class OFNOTIFY
        {
            public IntPtr hdr_hwndFrom = IntPtr.Zero;
            public IntPtr hdr_idFrom = IntPtr.Zero;
            public int hdr_code;
            public IntPtr lpOFN = IntPtr.Zero;
            public IntPtr pszFile = IntPtr.Zero;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public class OPENFILENAME_I
        {
            public int lStructSize = Marshal.SizeOf(typeof(NativeMethods.OPENFILENAME_I));
            public IntPtr hwndOwner;
            public IntPtr hInstance;
            public string lpstrFilter;
            public IntPtr lpstrCustomFilter = IntPtr.Zero;
            public int nMaxCustFilter;
            public int nFilterIndex;
            public IntPtr lpstrFile;
            public int nMaxFile = 260;
            public IntPtr lpstrFileTitle = IntPtr.Zero;
            public int nMaxFileTitle = 260;
            public string lpstrInitialDir;
            public string lpstrTitle;
            public int Flags;
            public short nFileOffset;
            public short nFileExtension;
            public string lpstrDefExt;
            public IntPtr lCustData = IntPtr.Zero;
            public NativeMethods.WndProc lpfnHook;
            public string lpTemplateName;
            public IntPtr pvReserved = IntPtr.Zero;
            public int dwReserved;
            public int FlagsEx;
        }

        [Serializable()]
        [StructLayout(LayoutKind.Sequential)]
        public struct LVITEM
        {
            public int mask;
            public int iItem;
            public int iSubItem;
            public int state;
            public int stateMask;
            public IntPtr pszText;
            public int cchTextMax;
            public int iImage;
            public IntPtr lParam;
            public int iIndent;
            public int iGroupId;
            public int cColumns;
            public IntPtr puColumns;
        }

        public class CharBuffer
        {
            // Fields
            internal char[] buffer;
            internal int offset;

            // Methods
            public CharBuffer(int size)
            {
                this.buffer = new char[size];
            }

            public IntPtr AllocCoTaskMem()
            {
                IntPtr destination = Marshal.AllocCoTaskMem(this.buffer.Length * 2);
                Marshal.Copy(this.buffer, 0, destination, this.buffer.Length);
                return destination;
            }

            public string GetString()
            {
                int offset = this.offset;
                while ((offset < this.buffer.Length) && (this.buffer[offset] != '\0'))
                {
                    offset++;
                }
                string str = new string(this.buffer, this.offset, offset - this.offset);
                if (offset < this.buffer.Length)
                {
                    offset++;
                }
                this.offset = offset;
                return str;
            }

            public void PutCoTaskMem(IntPtr ptr)
            {
                Marshal.Copy(ptr, this.buffer, 0, this.buffer.Length);
                this.offset = 0;
            }

            public void PutString(string s)
            {
                int count = Math.Min(s.Length, this.buffer.Length - this.offset);
                s.CopyTo(0, this.buffer, this.offset, count);
                this.offset += count;
                if (this.offset < this.buffer.Length)
                {
                    this.buffer[this.offset++] = '\0';
                }
            }
        }

        public static readonly IntPtr InvalidIntPtr = (IntPtr) (-1);
        public const int WM_COMMAND = 0x0111;

        public enum ListViewMessages : uint
        {
            LVM_FIRST = 0x1000,
            LVM_GETITEMCOUNT = LVM_FIRST + 4,
            LVM_GETITEM = LVM_FIRST + 5,
            LVM_GETITEMW = LVM_FIRST + 75,
            LVM_SETITEMPOSITION = LVM_FIRST + 15,
            LVM_GETITEMPOSITION = LVM_FIRST + 16,
            LVM_DELETEALLITEMS = LVM_FIRST + 9,
            LVM_INSERTITEM = LVM_FIRST + 77,
            LVM_ARRANGE = LVM_FIRST + 22,
            LVM_GETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 55,
            LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54,
            LVM_SETITEMTEXT = LVM_FIRST + 116,
            LVM_REDRAWITEMS = LVM_FIRST + 21
        }

        public static readonly uint LVIF_TEXT = 0x1, LVIF_IMAGE = 0x2, LVIF_STATE = 0x8, LVCF_FMT = 0x1, LVCF_WIDTH = 0x2, LVCF_TEXT = 0x4, LVCF_SUBITEM = 0x8, WM_USER = 0x0400, CDM_FIRST = (WM_USER + 100), CDM_GETFOLDERPATH = (CDM_FIRST + 0x0002);

        public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        public static object PtrToStructure(IntPtr lparam, Type cls)
        {
            return Marshal.PtrToStructure(lparam, cls);
        }

        public static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, HandleRef dwNewLong)
        {
            if (IntPtr.Size == 4)
            {
                return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
            }
            return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
        }

        [DllImport("user32.dll", ExactSpelling = true)]
        public static extern bool EndDialog(HandleRef hWnd, IntPtr result);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
        public static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, HandleRef dwNewLong);

        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
        public static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, HandleRef dwNewLong);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string modName);

        [DllImport("comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool GetOpenFileName([In, Out] NativeMethods.OPENFILENAME_I ofn);

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern IntPtr GetParent(HandleRef hWnd);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
    }
}
